<template>
  <el-select
    ref="treeSelect"
    :value="valueTitle"
    :placeholder="placeholder"
    :clearable="clearable"
    :disabled="disabled"
    popper-class="tree-select-wrapper-popper"
    @clear="clearHandle"
    @focus="initHandle"
    @visible-change="visiblChange"
  >
    <div class="search-input-wrap bgf">
      <el-input
        ref="inputSearch"
        v-model="filterText"
        class="search-input"
        placeholder="请输入关键字进行搜索"
        @keyup.native="doSearch"
      />
    </div>

    <el-option v-loading="optionLoading" :value="valueTitle" :label="valueTitle">
      <el-tree
        id="tree-option"
        ref="selectTree"
        :accordion="accordion"
        :data="options"
        :props="props"
        :default-expanded-keys="defaultExpandedkeys"
        :node-key="props.value"
        :highlight-current="true"
        :expand-on-click-node="expandOnClickNode"
        :default-expand-all="false"
        :filter-node-method="filterNode"
        :current-node-key="valueId"
        :load="loadNode"
        :lazy="lazy"
        @node-click="handleNodeClick"
      />
    </el-option>
  </el-select>
</template>

<script>
import { OrganizeSearchOrg, OrganizeSimpleTree } from "api/sys/organize";
import { debounce, cloneDeep } from "lodash";
import scrollIntoView from "libs/scroll-into-view";

export default {
  name: "TreeSelect",
  props: {
    // 配置项
    props: {
      type: Object,
      default: () => ({
        value: "id", // ID字段名
        label: "title", // 显示名称
        children: "children", // 子级字段名
        // 这里的改动可能会影响到全局
        isLeaf: "leaf",
      }),
    },
    // 选项列表数据(树形结构的对象数组)
    options: {
      type: Array,
      default: () => [],
    },
    // 初始值
    value: {
      type: [String, Number],
      default: "",
    },
    // 可清空选项
    clearable: {
      type: Boolean,
      default: true,
    },
    // 自动收起
    accordion: {
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
      default: "检索关键字",
    },
    // 懒加载
    lazy: {
      type: Boolean,
      default: false,
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 初始化组件数据
    initTreeData: {
      type: Function,
      default: () => ({}),
    },
    // 默认展开项
    defaultExpandedkeys: {
      type: Array,
      default: () => [],
    },
    expandOnClickNode: {
      type: Boolean,
      default: false,
    },
    // 获取树形数据API
    loadTreeApi: {
      type: Function,
      default: OrganizeSimpleTree,
    },
    // 树搜索API
    searchApi: {
      type: Function,
      default: OrganizeSearchOrg,
    },
    // 搜索的参数
    searchParamsKey: {
      type: String,
      default: "organizeName",
    },
    parentId: {
      type: [Number, String],
      default: 0,
    },
  },
  data() {
    return {
      filterText: "",
      valueId: this.value.toString(), // 初始值
      valueTitle: "",
      // 树形区域加载
      optionLoading: false,
    };
  },
  watch: {
    value() {
      this.valueId = this.value;
      this.initHandle();
    },
    options: {
      deep: true,
      handler() {
        this.valueId = this.value;
        this.initHandle();
      },
    },
  },
  methods: {
    /**
     * 初始化（非懒加载数据，在设置完树形数据后，手动执行下这个方法，即可设置上初始值显示）
     */
    async initHandle() {
      if (this.valueId) {
        let node = this.$refs.selectTree.getNode(this.valueId);
        if (node !== null) {
          this.valueTitle = node.data[this.props.label]; // 初始化显示
          this.setCurrentKey();
        }
      } else {
        this.valueTitle = ""; // 清除缓存显示
      }
    },
    /**
     * 设置默认选中
     */
    async setCurrentKey() {
      await this.$nextTick();
      this.$refs.selectTree && this.$refs.selectTree.setCurrentKey(this.valueId);
    },
    /**
     * 搜索
     */
    doSearch() {
      this.lazy ? this.doSyncSearch() : this.doLocalSearch();
    },
    /**
     * 远程搜索
     */
    doSyncSearch: debounce(async function () {
      try {
        this.optionLoading = true;
        if (this.filterText) {
          // 正常加载
          this.$refs.selectTree.store.lazy = false;
          this.$refs.selectTree.store.defaultExpandAll = true;
          await this.syncSearch({
            [this.searchParamsKey]: this.filterText,
            parentId: this.parentId,
          });
        } else {
          this.loadTreeData();
        }
      } catch (e) {
        console.log(e);
      } finally {
        this.optionLoading = false;
      }
    }, 300),
    /**
     * 本地搜索
     */
    doLocalSearch() {
      this.$refs.selectTree.filter(this.filterText);
    },
    /**
     * 加载树形数据
     */
    async loadTreeData() {
      // 懒加载
      this.$refs.selectTree.store.lazy = true;
      this.$refs.selectTree.store.defaultExpandAll = false;
      const treeData = await this.getTreeData();
      this.$emit("update:options", treeData);
      this.setActiveDataScrollIntoView();
    },
    /**
     * 搜索所属部门
     */
    async syncSearch(params) {
      try {
        const data = await this.searchApi(params);
        this.searchedTreeDataFormat(data);

        // 更新树形数据
        this.$emit("update:options", data);
      } catch (e) {
        console.log(e);
      }
    },
    /**
     * 格式化搜索的数据
     */
    searchedTreeDataFormat(data) {
      data.map((item) => {
        const { subCount, childList } = item;
        item.leaf = !subCount;
        if (childList && childList.length) {
          this.searchedTreeDataFormat(childList);
        }
      });
    },
    /**
     * 设置临时展示的内容，在懒加载中使用
     */
    setTempTitle(val) {
      this.valueTitle = val;
    },
    /**
     * 节点点击事件
     */
    handleNodeClick(node) {
      const { subCount } = node;
      if (!this.expandOnClickNode || !subCount) {
        this.valueTitle = node[this.props.label];
        this.valueId = Number(node[this.props.value]);
        this.$emit("getValue", node);
        // 自动隐藏
        this.$refs.treeSelect.blur();
      }
    },
    /**
     * 清除选中(点击清空按钮或者重置)
     */
    clearHandle(type = 0) {
      this.lazy && this.collapseAll();
      this.valueTitle = "";
      this.activeNode = "";
      this.valueId = "";
      this.$refs.selectTree.setCurrentKey();
      this.$emit("getValue", null, type);
    },
    /**
     * 全部折叠
     */
    collapseAll() {
      for (let i = 0; i < this.options.length; i++) {
        const {
          store: { nodesMap },
        } = this.$refs.selectTree;
        nodesMap[this.options[i].id].expanded = false;
      }
    },
    /**
     * 懒加载数据
     */
    async loadNode(node, resolve) {
      let defautVal = 0;

      const { data, level } = node;

      if (level !== 0) {
        defautVal = data[this.props.value];
      } else {
        // 存储第一层的node、resolve，用于type===1时，手动刷新数据
        this.node = node;
        this.resolve = resolve;
      }

      const tempData = await this.getTreeData({
        parentId: defautVal,
        parentName: data.fullName || data.name,
      });

      resolve(tempData);

      // 存储第一级数据，不用每次刷新都重新加载
      if (level === 0) {
        this.firstTreeData = cloneDeep(tempData);
      }

      this.setCurrentKey();
    },
    /**
     * 获取树形数据（其他的数据加载，在组件中重新定义）
     */
    async getTreeData({ parentId, parentName = "" } = {}) {
      try {
        const data = await this.loadTreeApi(parentId || this.parentId);
        let tempData = [];
        if (data && data.length) {
          data.map((item) => {
            const { name, subCount } = item;
            item.leaf = !subCount;
            item.fullName = parentName + name;
          });
          tempData = data;
        }
        return tempData;
      } catch (e) {
        console.log(e);
        return [];
      }
    },
    /**
     * popper显示隐藏
     */
    visiblChange(bool) {
      if (!bool) {
        // popper隐藏，恢复原始树形数据
        if (this.filterText) {
          // 清空搜索的值
          this.filterText = "";
          // 清空选中的节点
          this.activeNode = "";
          if (this.lazy) {
            // 设置回懒加载
            this.$refs.selectTree.store.lazy = true;
            // 设置回不全展开
            this.$refs.selectTree.store.defaultExpandAll = false;
            // 手动刷新数据
            this.node.childNodes = [];
            this.resolve(this.firstTreeData);
            this.setCurrentKey();
          } else {
            setTimeout(() => {
              this.doLocalSearch();
            }, 0);
          }
        }
      } else {
        // popper显示，控制scrollbar的位置
        setTimeout(() => {
          this.setActiveDataScrollIntoView();
          this.$refs.inputSearch.focus();
        }, 100);
      }
    },
    /**
     * 将选中项滚动到可见区
     */
    setActiveDataScrollIntoView() {
      if (this.$refs.treeSelect) {
        let parentDom = this.$refs.treeSelect.$children[1].$children[0];
        this.getActiveDom(parentDom.$children[1].$children[0].$children);
        const container = parentDom.$el.querySelector(".el-select-dropdown__wrap");
        // 取至element-ui源码中的方法
        scrollIntoView({
          container,
          selected: this.activeNode,
          paddingTop: 42,
        });
        parentDom.handleScroll();
      }
    },
    /**
     * 递归获取当前active的dom
     */
    getActiveDom(arr) {
      for (let i = 0; i < arr.length; i++) {
        const { $el, $children } = arr[i];
        if (Object.values($el.classList).includes("is-current")) {
          this.activeNode = $el;
          break;
        }
        if ($children.length) {
          this.getActiveDom($children);
        }
      }
    },
    /**
     * 过滤节点
     */
    filterNode(value, data) {
      if (!value) return true;
      return data[this.props.label].indexOf(value) !== -1;
    },
  },
};
</script>

<style lang="scss" scoped>
.tree-select-wrapper-popper {
  .el-scrollbar__view {
    position: relative;
  }
  .search-input-wrap {
    position: absolute;
    top: 0;
    left: 0;
    padding: 5px 10px;

    width: 100%;
    z-index: 1;
  }

  .el-select-dropdown__wrap {
    .el-select-dropdown__list {
      padding-top: 0;
    }
  }

  .el-select-dropdown__item {
    height: 100%;
    padding: 0;
    padding-top: 36px;
    background: #fff;

    &.selected {
      font-weight: normal;
    }
    .el-tree {
      ::v-deep .el-tree-node__content {
        padding-right: 15px;
      }
      ::v-deep .is-current {
        .el-tree-node__label {
          color: #409eff;
        }
        .el-tree-node__children {
          .el-tree-node__label {
            color: #606266;
            padding-right: 10px;
            font-weight: normal;
          }
        }
      }
    }
  }
}
</style>
